using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using JGSY.CMS.LowCode.Platform.Application.DTOs;
using JGSY.CMS.LowCode.Platform.Application.Interfaces;
using JGSY.CMS.LowCode.Platform.Domain.Entities;
using JGSY.CMS.LowCode.Platform.Infrastructure.CmsDbContext;
using Microsoft.EntityFrameworkCore;

namespace JGSY.CMS.LowCode.Platform.Application.Services
{
    /// <summary>
    /// 操作日志应用服务实现
    /// 提供操作日志的业务逻辑操作
    /// </summary>
    public class OperationLogAppService : IOperationLogAppService
    {
        private readonly LowCodeDbContext _dbContext;
        private readonly ILogger<OperationLogAppService> _logger;

        public OperationLogAppService(
            LowCodeDbContext dbContext,
            ILogger<OperationLogAppService> logger)
        {
            _dbContext = dbContext;
            _logger = logger;
        }

        /// <summary>
        /// 记录操作日志
        /// 用于记录系统中各种操作的详细信息，支持完整的操作审计跟踪
        /// </summary>
        /// <param name="operationType">操作类型，如"Create"、"Update"、"Delete"等</param>
        /// <param name="operationName">操作名称，具体的操作描述</param>
        /// <param name="description">操作描述，可选的详细说明</param>
        /// <param name="userId">用户标识符，执行操作的用户ID</param>
        /// <param name="userName">用户名称，执行操作的用户名</param>
        /// <param name="tenantId">租户标识符，多租户场景下的租户ID</param>
        /// <param name="correlationId">关联标识符，用于跟踪相关操作</param>
        /// <param name="requestPath">请求路径，API接口路径</param>
        /// <param name="httpMethod">HTTP方法，如GET、POST、PUT、DELETE等</param>
    /// <param name="duration">操作耗时（毫秒），可选</param>
    /// <param name="success">操作是否成功，默认 true</param>
    /// <param name="additionalData">附加数据（如请求/响应内容），用于追踪与审计</param>
    /// <returns>操作日志记录的ID</returns>
        public async Task<long> LogOperationAsync(
            string operationType,
            string operationName,
            string? description = null,
            string? userId = null,
            string? userName = null,
            string? tenantId = null,
            string? correlationId = null,
            string? requestPath = null,
            string? httpMethod = null,
            long? duration = null,
            bool success = true,
            Dictionary<string, object>? additionalData = null)
        {
            try
            {
                var operationLog = new OperationLog
                {
                    TraceId = Guid.NewGuid().ToString(),
                    CorrelationId = correlationId,
                    OperationType = operationType,
                    OperationName = operationName,
                    Description = description,
                    UserId = userId,
                    UserName = userName,
                    TenantId = tenantId ?? string.Empty,
                    RequestPath = requestPath,
                    HttpMethod = httpMethod,
                    Duration = duration,
                    Success = success,
                    ErrorMessage = success ? null : "操作失败",
                    RequestData = additionalData?.TryGetValue("RequestData", out var reqData) == true ? 
                        System.Text.Json.JsonSerializer.Serialize(reqData) : null,
                    ResponseData = additionalData?.TryGetValue("ResponseData", out var respData) == true ? 
                        System.Text.Json.JsonSerializer.Serialize(respData) : null,
                    AdditionalData = additionalData != null ? System.Text.Json.JsonSerializer.Serialize(additionalData) : null,
                    IpAddress = GetIpAddressFromAdditionalData(additionalData),
                    UserAgent = GetUserAgentFromAdditionalData(additionalData),
                    Timestamp = DateTime.UtcNow
                };

                _dbContext.OperationLogs.Add(operationLog);
                await _dbContext.SaveChangesAsync();

                return operationLog.Id;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "记录操作日志时发生错误");
                return 0;
            }
        }

        /// <summary>
        /// 记录用户操作日志
        /// 根据操作上下文记录用户的具体操作，包含完整的上下文信息
        /// </summary>
        /// <param name="context">操作上下文，包含操作的所有相关信息</param>
        /// <returns>操作日志记录的ID</returns>
        public async Task<long> LogUserOperationAsync(OperationContext context)
        {
            try
            {
                var operationLog = new OperationLog
                {
                    TraceId = context.TraceId ?? Guid.NewGuid().ToString(),
                    CorrelationId = context.CorrelationId,
                    OperationType = context.OperationType,
                    OperationName = context.OperationName,
                    Description = context.Description,
                    UserId = context.UserId,
                    UserName = context.UserName,
                    TenantId = context.TenantId ?? string.Empty,
                    RequestPath = context.RequestPath,
                    HttpMethod = context.HttpMethod,
                    Duration = context.Duration,
                    Success = context.Success,
                    ErrorMessage = context.ErrorMessage,
                    RequestData = context.RequestData != null ? System.Text.Json.JsonSerializer.Serialize(context.RequestData) : null,
                    ResponseData = context.ResponseData != null ? System.Text.Json.JsonSerializer.Serialize(context.ResponseData) : null,
                    AdditionalData = context.AdditionalData != null ? System.Text.Json.JsonSerializer.Serialize(context.AdditionalData) : null,
                    IpAddress = context.IpAddress,
                    UserAgent = context.UserAgent,
                    Timestamp = context.Timestamp
                };

                _dbContext.OperationLogs.Add(operationLog);
                await _dbContext.SaveChangesAsync();

                return operationLog.Id;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "记录用户操作日志时发生错误");
                return 0;
            }
        }

        /// <summary>
        /// 获取指定ID的操作日志
        /// 根据日志ID获取单条操作日志的详细信息
        /// </summary>
        /// <param name="id">操作日志ID</param>
        /// <returns>操作日志DTO对象，如果不存在则返回null</returns>
        public async Task<OperationLogDto?> GetOperationLogAsync(long id)
        {
            try
            {
                var operationLog = await _dbContext.OperationLogs.FindAsync(id);
                if (operationLog == null) return null;

                return MapToDto(operationLog);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取操作日志时发生错误，ID: {Id}", id);
                return null;
            }
        }

        /// <summary>
        /// 分页获取操作日志列表
        /// 支持多条件筛选和分页查询，用于日志管理和审计
        /// </summary>
        /// <param name="tenantId">租户ID，可选的租户筛选条件</param>
        /// <param name="userId">用户ID，可选的用户筛选条件</param>
        /// <param name="operationType">操作类型，可选的操作类型筛选条件</param>
        /// <param name="startTime">开始时间，可选的时间范围筛选</param>
        /// <param name="endTime">结束时间，可选的时间范围筛选</param>
        /// <param name="success">操作是否成功，可选的成功状态筛选</param>
        /// <param name="pageIndex">页码，从1开始</param>
        /// <param name="pageSize">每页大小，默认20</param>
        /// <returns>包含日志列表和总数的元组</returns>
        public async Task<(List<OperationLogDto> Items, int TotalCount)> GetOperationLogsAsync(
            string? tenantId = null,
            string? userId = null,
            string? operationType = null,
            DateTime? startTime = null,
            DateTime? endTime = null,
            bool? success = null,
            int pageIndex = 1,
            int pageSize = 20)
        {
            try
            {
                var query = _dbContext.OperationLogs.AsQueryable();

                if (!string.IsNullOrEmpty(tenantId))
                    query = query.Where(x => x.TenantId == tenantId);

                if (!string.IsNullOrEmpty(userId))
                    query = query.Where(x => x.UserId == userId);

                if (!string.IsNullOrEmpty(operationType))
                    query = query.Where(x => x.OperationType == operationType);

                if (success.HasValue)
                    query = query.Where(x => x.Success == success.Value);

                if (startTime.HasValue)
                    query = query.Where(x => x.Timestamp >= startTime.Value);

                if (endTime.HasValue)
                    query = query.Where(x => x.Timestamp <= endTime.Value);

                var totalCount = await query.CountAsync();

                var items = await query
                    .OrderByDescending(x => x.Timestamp)
                    .Skip((pageIndex - 1) * pageSize)
                    .Take(pageSize)
                    .Select(x => MapToDto(x))
                    .ToListAsync();

                return (items, totalCount);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取操作日志列表时发生错误");
                return (new List<OperationLogDto>(), 0);
            }
        }

        public async Task<List<OperationLogDto>> GetOperationLogsByCorrelationIdAsync(string correlationId)
        {
            try
            {
                var items = await _dbContext.OperationLogs
                    .Where(x => x.CorrelationId == correlationId)
                    .OrderByDescending(x => x.Timestamp)
                    .Select(x => MapToDto(x))
                    .ToListAsync();

                return items;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "根据关联ID获取操作日志时发生错误，CorrelationId: {CorrelationId}", correlationId);
                return new List<OperationLogDto>();
            }
        }

        public async Task<OperationStatistics> GetOperationStatisticsAsync(
            string? tenantId = null,
            string? userId = null,
            DateTime? startTime = null,
            DateTime? endTime = null)
        {
            try
            {
                var query = _dbContext.OperationLogs.AsQueryable();

                if (!string.IsNullOrEmpty(tenantId))
                    query = query.Where(x => x.TenantId == tenantId);

                if (!string.IsNullOrEmpty(userId))
                    query = query.Where(x => x.UserId == userId);

                if (startTime.HasValue)
                    query = query.Where(x => x.Timestamp >= startTime.Value);

                if (endTime.HasValue)
                    query = query.Where(x => x.Timestamp <= endTime.Value);

                var statistics = new OperationStatistics
                {
                    TotalOperations = await query.CountAsync(),
                    SuccessfulOperations = await query.Where(x => x.Success == true).CountAsync(),
                    FailedOperations = await query.Where(x => x.Success == false).CountAsync()
                };

                // 操作类型统计
                statistics.OperationTypeCount = await query
                    .GroupBy(x => x.OperationType)
                    .Select(g => new { Type = g.Key ?? "Unknown", Count = g.Count() })
                    .ToDictionaryAsync(x => x.Type, x => x.Count);

                // 用户操作统计
                statistics.UserOperationCount = await query
                    .Where(x => !string.IsNullOrEmpty(x.UserId))
                    .GroupBy(x => x.UserId)
                    .Select(g => new { UserId = g.Key ?? "Unknown", Count = g.Count() })
                    .ToDictionaryAsync(x => x.UserId, x => x.Count);

                // 按小时统计
                if (startTime.HasValue && endTime.HasValue)
                {
                    statistics.OperationsByHour = await query
                        .GroupBy(x => x.Timestamp.Hour)
                        .Select(g => new { Hour = g.Key.ToString(), Count = g.Count() })
                        .ToDictionaryAsync(x => x.Hour, x => x.Count);
                }

                // 平均耗时统计
                var durationsQuery = query.Where(x => x.Duration.HasValue);
                if (await durationsQuery.AnyAsync())
                {
                    statistics.AverageDuration = await durationsQuery.AverageAsync(x => x.Duration!.Value);
                    statistics.MaxDuration = await durationsQuery.MaxAsync(x => x.Duration!.Value);
                    statistics.MinDuration = await durationsQuery.MinAsync(x => x.Duration!.Value);
                }

                return statistics;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取操作统计信息时发生错误");
                return new OperationStatistics();
            }
        }

        public async Task<PerformanceStatistics> GetPerformanceStatisticsAsync(
            string? tenantId = null,
            string? operationType = null,
            DateTime? startTime = null,
            DateTime? endTime = null)
        {
            try
            {
                var query = _dbContext.OperationLogs.Where(x => x.Duration.HasValue);

                if (!string.IsNullOrEmpty(tenantId))
                    query = query.Where(x => x.TenantId == tenantId);

                if (!string.IsNullOrEmpty(operationType))
                    query = query.Where(x => x.OperationType == operationType);

                if (startTime.HasValue)
                    query = query.Where(x => x.Timestamp >= startTime.Value);

                if (endTime.HasValue)
                    query = query.Where(x => x.Timestamp <= endTime.Value);

                if (!await query.AnyAsync())
                    return new PerformanceStatistics();

                var statistics = new PerformanceStatistics
                {
                    AverageResponseTime = await query.AverageAsync(x => x.Duration!.Value),
                    MaxResponseTime = await query.MaxAsync(x => x.Duration!.Value),
                    MinResponseTime = await query.MinAsync(x => x.Duration!.Value),
                    TotalRequests = await query.CountAsync()
                };

                // 按操作类型的平均响应时间
                statistics.AverageResponseTimeByOperation = await query
                    .GroupBy(x => x.OperationType)
                    .Select(g => new { Type = g.Key ?? "Unknown", AvgTime = g.Average(x => x.Duration!.Value) })
                    .ToDictionaryAsync(x => x.Type, x => x.AvgTime);

                // 按小时的请求数量
                if (startTime.HasValue && endTime.HasValue)
                {
                    statistics.RequestCountByHour = await query
                        .GroupBy(x => x.Timestamp.Hour)
                        .Select(g => new { Hour = g.Key.ToString(), Count = g.Count() })
                        .ToDictionaryAsync(x => x.Hour, x => x.Count);
                }

                // 最慢的操作
                statistics.SlowestOperations = await query
                    .OrderByDescending(x => x.Duration)
                    .Take(10)
                    .Select(x => new SlowOperationInfo
                    {
                        OperationName = x.OperationName ?? "Unknown",
                        Duration = x.Duration!.Value,
                        Timestamp = x.Timestamp,
                        UserId = x.UserId,
                        RequestPath = x.RequestPath
                    })
                    .ToListAsync();

                return statistics;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取性能统计信息时发生错误");
                return new PerformanceStatistics();
            }
        }

        public async Task<int> LogBatchOperationsAsync(IEnumerable<OperationContext> operations)
        {
            try
            {
                var operationLogs = operations.Select(context => new OperationLog
                {
                    TraceId = context.TraceId ?? Guid.NewGuid().ToString(),
                    CorrelationId = context.CorrelationId,
                    OperationType = context.OperationType,
                    OperationName = context.OperationName,
                    Description = context.Description,
                    UserId = context.UserId,
                    UserName = context.UserName,
                    TenantId = context.TenantId ?? string.Empty,
                    RequestPath = context.RequestPath,
                    HttpMethod = context.HttpMethod,
                    Duration = context.Duration,
                    Success = context.Success,
                    ErrorMessage = context.ErrorMessage,
                    RequestData = context.RequestData != null ? System.Text.Json.JsonSerializer.Serialize(context.RequestData) : null,
                    ResponseData = context.ResponseData != null ? System.Text.Json.JsonSerializer.Serialize(context.ResponseData) : null,
                    AdditionalData = context.AdditionalData != null ? System.Text.Json.JsonSerializer.Serialize(context.AdditionalData) : null,
                    IpAddress = context.IpAddress,
                    UserAgent = context.UserAgent,
                    Timestamp = context.Timestamp
                }).ToList();

                _dbContext.OperationLogs.AddRange(operationLogs);
                await _dbContext.SaveChangesAsync();

                return operationLogs.Count;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量记录操作日志时发生错误");
                return 0;
            }
        }

        private string? GetUserAgentFromAdditionalData(Dictionary<string, object>? additionalData)
        {
            return additionalData?.TryGetValue("UserAgent", out var userAgent) == true ? userAgent?.ToString() : null;
        }

        private string? GetIpAddressFromAdditionalData(Dictionary<string, object>? additionalData)
        {
            return additionalData?.TryGetValue("IpAddress", out var ipAddress) == true ? ipAddress?.ToString() : null;
        }

        private OperationLogDto MapToDto(OperationLog entity)
        {
            return new OperationLogDto
            {
                Id = entity.Id,
                TraceId = entity.TraceId,
                CorrelationId = entity.CorrelationId,
                OperationType = entity.OperationType,
                OperationName = entity.OperationName,
                Description = entity.Description,
                UserId = entity.UserId,
                UserName = entity.UserName,
                TenantId = entity.TenantId,
                RequestPath = entity.RequestPath,
                HttpMethod = entity.HttpMethod,
                Duration = entity.Duration,
                Success = entity.Success,
                ErrorMessage = entity.ErrorMessage,
                RequestData = entity.RequestData,
                ResponseData = entity.ResponseData,
                AdditionalData = entity.AdditionalData,
                IpAddress = entity.IpAddress,
                UserAgent = entity.UserAgent,
                Timestamp = entity.Timestamp
            };
        }
    }
}
